package cn.bluethink.eguan.core.service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;

import cn.bluethink.eguan.core.entity.CommentEntity;
import cn.bluethink.eguan.core.entity.EgCommentEntity;
import cn.bluethink.eguan.core.mapper.EgCommentMapper;
import cn.bluethink.eguan.filter.OtypeFilter;
import cn.bluethink.eguan.model.core.EgActionType;
import cn.bluethink.eguan.model.core.EgComment;
import cn.bluethink.eguan.model.core.EgConfigInfo;
import cn.bluethink.eguan.model.core.EgOType;
import cn.bluethink.eguan.model.core.EgObject;
import cn.bluethink.eguan.model.core.EgOtAction;
import cn.bluethink.eguan.model.core.EgTask;
import cn.bluethink.eguan.model.core.EgUser;
import cn.bluethink.eguan.result.PageInfo;
import cn.bluethink.eguan.utils.IdMakerUtils;
import tk.mybatis.mapper.entity.Example;

@Service
public class EgCommentService {

    @Autowired
    private EgCommentMapper commentMapper;

    @Autowired
    private EgActionService actionService;

    @Autowired
    private EgUserService userService;

    @Autowired
    private EgPosObjectService objService;

    @Autowired
    private EgConfigInfo configInfo;

    private IdMakerUtils idUtil = new IdMakerUtils();

    /**
     * 发布评论
     * 
     * @param comment
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public EgComment create(EgComment comment, Long uid) throws Exception {
        // 1、使用Id生成器生成id
        Long uuid = idUtil.nextId();
        comment.setId(uuid);
        Long oid = comment.getObj() == null ? null : comment.getObj().getId();
        EgOType otype = comment.getObj() == null ? null : comment.getObj().getType();
        // 2、模型转实体
        EgCommentEntity entity = new EgCommentEntity(comment, null, null);
        // 3、如果被评论的对象类型为 评论
        if (otype.getOtid() == EgOType.COMMENT) {
            // 4、查询被评论的对象
            EgCommentEntity commentEntity = commentMapper.selectByPrimaryKey(comment.getObj().getId());
            if (commentEntity == null)
                return null;
            entity.setCommentator(commentEntity.getUid());
            // 5、如果被评论的对象不为空，设置其根对象为被评论对象的根对象
            if (commentEntity.getOtype() == EgOType.COMMENT) {
                entity.setRootOid(commentEntity.getRootOid());
                entity.setRootOtype(commentEntity.getRootOtype());
            } else {
                entity.setRootOid(commentEntity.getCmid());
                entity.setRootOtype(EgOType.COMMENT);
            }
        }
        // 6、否则，被评论的对象即为其根对象
        else {
            entity.setRootOid(comment.getObj().getId());
            entity.setRootOtype(otype.getOtid());
        }
        // 7、发布评论
        entity.setUid(uid);
        int result = commentMapper.insert(entity);
        // 8、发布失败，返回null；否则，返回评论对象
        if (result == 0)
            return null;
        comment.setId(entity.getCmid());

        // 获取被操作的对象
        EgObject obj = objService.pos(otype.getOtid(), oid);
        if (obj == null) {
            return comment;
        }
        if (!saveAction(obj, comment, uid)) {
            throw new RuntimeException("新增动作失败！");
        }
        return comment;
    }

    /**
     * 修改评论
     * 
     * @param comment
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public EgComment update(EgComment comment) throws Exception {
        // 1、模型转实体
        EgCommentEntity entity = new EgCommentEntity(comment, null, null);
        // 2、修改评论
        int result = commentMapper.updateByPrimaryKeySelective(entity);
        // 3、修改失败，返回null；否则，返回评论对象
        if (result == 0)
            return null;
        return comment;
    }

    /**
     * 删除评论
     * 
     * @param cmid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public Long del(Long cmid) throws Exception {
        int result = 0;
        EgCommentEntity entity = commentMapper.selectByPrimaryKey(cmid);
        // 如果该评论的
        if (entity.getRootOtype() == EgOType.COMMENT) {
            result = commentMapper.deleteByPrimaryKey(cmid);
        } else {
            Example example = new Example(EgCommentEntity.class);
            example.and().andEqualTo("rootOid", cmid);
            example.and().andEqualTo("rootOtype", EgOType.COMMENT);
            // 删除该评论下的所有回复
            commentMapper.deleteByExample(example);
            // 删除评论
            result = commentMapper.deleteByPrimaryKey(cmid);
        }
        if (result == 0)
            return null;
        return cmid;
    }

    /**
     * 根据被评论的对象删除其下所有评论
     * 
     * @param obj
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public Long deleteByObj(EgObject obj) throws Exception {
        if (obj == null || obj.getId() == 0 || obj.getType().getOtid() == 0)
            return null;
        Example example = new Example(EgCommentEntity.class);
        example.and().andEqualTo("rootOid", obj.getId());
        example.and().andEqualTo("rootOtype", obj.getType().getOtid());
        commentMapper.deleteByExample(example);
        return obj.getId();
    }

    /**
     * 根据根对象列表查询对应的所有评论
     * 
     * @param rootOtype
     * @param rootOids
     * @return
     * @throws Exception
     */
    public Integer queryByRootObjs(Integer rootOtype, List<Long> rootOids) throws Exception {
        Example example = new Example(EgCommentEntity.class);
        example.and().andEqualTo("rootOtype", rootOtype).andIn("rootOid", rootOids);
        int selectCount = commentMapper.selectCountByExample(example);
        return selectCount;
    }
    
    /**
     * 根据根对象列表删除对应的所有评论
     * 
     * @param rootOtype
     * @param rootOids
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public Boolean delByRootObjs(Integer rootOtype, List<Long> rootOids) throws Exception {
        Example example = new Example(EgCommentEntity.class);
        example.and().andEqualTo("rootOtype", rootOtype).andIn("rootOid", rootOids);
        int delCount = commentMapper.deleteByExample(example);
        return delCount > 0 ? true : false;
    }

    /**
     * 查看评论详情
     */
    public EgComment detail(Long cmid) throws Exception {
        EgCommentEntity commentEntity = commentMapper.selectByPrimaryKey(cmid);
        if (commentEntity == null)
            return null;
        return commentEntity.createComment();
    }

    /**
     * 根据过滤条件获取评论列表
     * 
     * @param comment
     * @return
     * @throws Exception
     */
    public PageInfo<EgComment> query(OtypeFilter filter) throws Exception {
        Integer pageNum = filter.getPageNum() == null ? 1 : filter.getPageNum();
        Integer pageSize = filter.getPageSize() == null ? 20 : filter.getPageSize();
        // 1、构造查询条件
        String whereSql = buildQuerySQL(filter);
        if(whereSql == null || whereSql.equals("")) return new PageInfo<>(new ArrayList<>());
        
        PageHelper.startPage(pageNum, pageSize);
        Page<CommentEntity> entities = commentMapper.query(whereSql);
        if (entities != null && entities.size() > 0) {
            List<EgComment> result = entities.stream().map(e -> e.createComment()).collect(Collectors.toList());
            return new PageInfo<>(result, entities);
        }
        return new PageInfo<>(new ArrayList<>());
    }

    /**
     * 根据过滤条件构建查询条件
     * 
     * @param filter
     * @return
     * @throws Exception
     */
    private String buildQuerySQL(OtypeFilter filter) throws Exception {
        String whereSql = "";

        List<String> whereSqlList = new ArrayList<>();

        // 1、声明过滤条件（根据被评论的跟对象Id和类型查询其下所有的评论列表）
        Integer otype = filter.getOtype() == null ? 0 : filter.getOtype();
        Long id = filter.getId() == null ? 0 : filter.getId();
        Boolean buid = filter.getBuid() == null ? false : filter.getBuid();

        // 2、判断Id是否大于0
        if (id > 0) {
            // 3、判断是否为发布者Id，是发布者Id，根据 发布者ID查询其发布的工作任务列表
            if (buid) {
                whereSqlList.add(" eu.uid = " + id);
            } else if (!buid && otype > 0) {
                // 4、否则，根据驿馆Id和驿馆类型查询驿馆中的工作任务列表
                whereSqlList.add(" ec.root_oid = " + id);
                whereSqlList.add(" ec.root_otype = " + otype);
            }
        }
        // 5、设置查询条件AND连接符
        if (whereSqlList.size() > 0) {
            whereSql += String.join(" AND ", whereSqlList);
        }

        whereSql += " ORDER BY";
        whereSql += " ec.ctime DESC";
        return whereSql;
    }

    /**
     * 保存动作：评论对象(评论只作为动态)
     * 
     * @param obj
     * @param cmid
     * @param uid
     * @return
     * @throws Exception
     */
    private Boolean saveAction(EgObject obj, EgComment comment, Long uid) throws Exception {
        // 操作者信息
        EgUser user = userService.getUser(uid, false);
        if (user == null) {
            return false;
        }
        // 动作为评论
        int atid = EgActionType.COMMENT;
        // 动作名称
        String actionName = configInfo.actionTypes().get(atid).getName();
        // 被操作对象的类型名称
        String otypeName = configInfo.otypes().get(EgOType.OKR_TASK).getName();
        // 被操作对象名称
        String oname = obj.getName();
        EgOtAction otAction = configInfo.actionTypes(EgOType.OKR_TASK).get(atid);
        // 结果对象类型
        EgOType rtype = otAction.getRtype();
        // 动作标识
        Integer actFlag = otAction.getFlag();
        // 结果对象
        EgObject result = new EgObject(comment.getId(), comment.getName(), rtype);
        // 拼接操作结果
        String rcontent = user.getName() + " " + actionName + "了 " + otypeName + " " + oname;
        if (obj instanceof EgTask) {
            // 将对象强转成任务
            EgTask task = (EgTask) obj;
            // 动作发生的位置
            EgObject pos = task.getPos();
            if (!actionService.create(atid, obj, result, rcontent, pos, uid, actFlag)) {
                return false;
            }
            return true;
        }
        return false;
    }
}
